
#include "script.h"
#include "script_cmd.h"


static void ringScriptROR(RingScript *self, uint32_t script)
{
  uint32_t i, j;
  uint32_t times;
  uint32_t length;
  uint32_t tmp_pixel;

  times = (script >> 8) & 0xff;
  length = script >> 16;

  for(i = 0; i < times; i++)
  {
    tmp_pixel = self->pixels[self->ndx % RS_PIXEL_MAX];
    for(j = self->ndx; j < self->ndx + length - 1; j++)
    {
      self->pixels[j % RS_PIXEL_MAX] = self->pixels[(j + 1) % RS_PIXEL_MAX];
    }
    self->pixels[j % RS_PIXEL_MAX] = tmp_pixel;
  }
}

static void ringScriptROL(RingScript *self, uint32_t script)
{
  uint32_t i, j;
  uint32_t times;
  uint32_t length;
  uint32_t tmp_pixel;

  times = (script >> 8) & 0xff;
  length = script >> 16;

  for(i = 0; i < times; i++)
  {
    tmp_pixel = self->pixels[(self->ndx + length - 1) % RS_PIXEL_MAX];
    for(j = self->ndx + length - 1; j > self->ndx; j--)
    {
      self->pixels[j % RS_PIXEL_MAX] = self->pixels[(j - 1) % RS_PIXEL_MAX];
    }
    self->pixels[j % RS_PIXEL_MAX] = tmp_pixel;
  }
}

static void ringScriptSetPC(RingScript *self, uint32_t pc)
{
  if(pc > 0 && pc < 65536)
  {
    self->pc = pc;
  }
  else
  {
    self->pc = 1;
  }
}

int ringScriptInit(RingScript *self, const uint32_t scripts[])
{
  if(scripts[0] == RS_CMD_MAG)
  {
    self->cnt = self->ndx = 0;
    self->pc = 1; // 第1条指令为魔数
    self->pc_djnz = 0;
    self->scripts = scripts;
    return 0;
  }
  else
  {
    return -1;
  }
}

uint32_t ringScriptRun(RingScript *self)
{
  uint32_t cmd;
  uint32_t script;
  uint32_t num;
  uint32_t i;
  uint32_t sleep_ticks = 0;

  if(self->scripts[0] != RS_CMD_MAG)
  {
    return 100;
  }

  script = self->scripts[self->pc];
  cmd = script & 0xff;
  self->pc++;

  switch(cmd)
  {
  case RS_CMD_NDX:
    self->ndx = script >> 16;
    if(self->ndx >= RS_PIXEL_MAX)
    {
      self->ndx = self->ndx % RS_PIXEL_MAX;
    }
    break;

  case RS_CMD_RGB:
    self->pixels[self->ndx] = script & 0xffffff00; // 寄存器布局'BGRA'，内存布局从低到高'ARGB'， Alpha在最低字节，Blue在最高字节
    self->ndx++;
    if(self->ndx >= RS_PIXEL_MAX)
    {
      self->ndx = 0;
    }
    break;

  case RS_CMD_CLR:
    num = script >> 16;
    if(self->ndx + num > RS_PIXEL_MAX)
    {
      num = RS_PIXEL_MAX - self->ndx;
    }
    for(i = self->ndx; i < self->ndx + num; i++)
    {
      self->pixels[i] = 0;
    }
    break;

  case RS_CMD_ROR:
    ringScriptROR(self, script);
    break;

  case RS_CMD_ROL:
    ringScriptROL(self, script);
    break;

  case RS_CMD_CNT:
    self->cnt = script >> 16;
    self->pc_djnz = self->pc;
    break;

  case RS_CMD_DJNZ:
    if(self->cnt > 0)
    {
      self->cnt--;
      if(self->cnt != 0)
      {
        ringScriptSetPC(self, self->pc_djnz);
      }
    }
    break;

  case RS_CMD_RJMP:
    ringScriptSetPC(self, self->pc - (script >> 16) - 1);
    break;

  case RS_CMD_AJMP:
    ringScriptSetPC(self, script >> 16);
    break;

  case RS_CMD_TCK:
    ringScriptPortOutput(self->pixels);
    sleep_ticks = script >> 16;
    break;

  case RS_CMD_NOP:
    sleep_ticks = script >> 16;
    break;

  case RS_CMD_LOOP:
    self->pc_loop = self->pc;
    break;

  case RS_CMD_END:
    ringScriptSetPC(self, self->pc_loop);
    break;

  case RS_CMD_BEEP:
  {
    uint32_t pin, state;
    pin = (script >> 16) & 0xff;
    state = script >> 24;
    ringScriptPortBeep(pin, state);
  }
  break;

  default:
    break;
  }

  return sleep_ticks;
}

